package com.devshephard.rpcframework.servletsync.controller;


import com.devshephard.rpcframework.servletsync.service.SyncServlet;
import com.devshephard.rpcframework.servletsync.service.impl.SimpleSyncServletImpl;
import com.devshephard.rpcframework.servletsync.service.impl.SyncServletImpl;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.Callable;

import static org.springframework.web.bind.annotation.RequestMethod.GET;

@RestController
@Slf4j
public class SyncServletController extends HttpServlet {

    @Autowired
    SyncServlet syncServlet;

    @Autowired
    SyncServletImpl syncServletImpl;

    @Autowired
    SimpleSyncServletImpl simpleSyncServlet;


    @SneakyThrows
    @RequestMapping(value = "/SyncServlet")
    @ResponseBody
    public void doAsyncServlet(HttpServletRequest request, HttpServletResponse response){

        log.info(Thread.currentThread().getName());

        /**
         * 使用基本的ServletAsync机制
         */
        //AsyncContext asyncContext = request.startAsync();
        //Runnable runnable = () -> {
        // new LongRunningProcess().run();
        // try {
        //     asyncContext.getResponse().getWriter().write(Thread.currentThread().getName() +"Hello World!");
        //  } catch (IOException e) {
        //      e.printStackTrace();
        //   }
        //   asyncContext.complete();

        //    };
        // new Thread(runnable).start()

        //this.setAsyncServlet(request,response);


        /**
         * 使用封装的ServletAsync机制
         */
        /*new SyncServletImpl() {
            @Override
            public String callBack() {
                return "test callback!";
            }

            @Override
            public void afterExecute() {
                System.out.println(Thread.currentThread().getName() +" 执行afterExecute方法");
            }
        }.executeChain(request,response);*/


        /**
         * 使用减少内存使用的ServletAsync机制
         */
        log.info(String.valueOf(this.hashCode()));
        simpleSyncServlet.executeChain(request,response,"Doge！！",this,"testMd");

        System.out.println("主线程：" + Thread.currentThread().getName());

    }

    @SneakyThrows
    @RequestMapping(value = "/SyncServlet2")
    @ResponseBody
    public void doAsyncServlet2(HttpServletRequest request, HttpServletResponse response){

        log.info(Thread.currentThread().getName());

        Thread.sleep(1000);
        /**
         * 使用减少内存使用的ServletAsync机制
         */
        log.info(String.valueOf(this.hashCode()));
        simpleSyncServlet.executeChain(request,response,"Shiba！！",this,"testMd");

        System.out.println("主线程：" + Thread.currentThread().getName());

    }


    public void setAsyncServlet(HttpServletRequest request, HttpServletResponse response){

        AsyncContext asyncContext = request.startAsync();

        Runnable runnable = () -> {
            try {
                asyncContext.getResponse().getWriter().write(Thread.currentThread().getName() +"Hello World!");
            } catch (IOException e) {
                e.printStackTrace();
            }
            asyncContext.complete();
        };

        new Thread(runnable).start();
    }

    @RequestMapping(value = "/SyncServlet/servletReq", method = GET)
    public void servletReq (HttpServletRequest request, HttpServletResponse response) throws InterruptedException {
        AsyncContext asyncContext = request.startAsync();
        //设置监听器:可设置其开始、完成、异常、超时等事件的回调处理
        asyncContext.addListener(new AsyncListener() {
            @Override
            public void onTimeout(AsyncEvent event) throws IOException {
                System.out.println("超时了...");
                //做一些超时后的相关操作...
            }
            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {
                System.out.println("线程开始");
            }
            @Override
            public void onError(AsyncEvent event) throws IOException {
                System.out.println("发生错误："+event.getThrowable());
            }
            @Override
            public void onComplete(AsyncEvent event) throws IOException {
                System.out.println("执行完成");
                //这里可以做一些清理资源的操作...
            }
        });
        //设置超时时间
        asyncContext.setTimeout(20000);
        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("内部线程：" + Thread.currentThread().getName());
                    asyncContext.getResponse().setCharacterEncoding("utf-8");
                    asyncContext.getResponse().setContentType("text/html;charset=UTF-8");
                    asyncContext.getResponse().getWriter().println(Thread.currentThread().getName() + "这是异步的请求返回");
                } catch (Exception e) {
                    System.out.println("异常："+e);
                }
                //异步请求完成通知
                //此时整个请求才完成
                asyncContext.complete();
            }
        });
        //此时之类 request的线程连接已经释放了
        System.out.println("主线程：" + Thread.currentThread().getName());

        for (int i = 0; i < 1000; i++) {
            System.out.println("kksk");
        };

    }


    @RequestMapping(value = "/SyncServlet/callableReq", method = GET)
    @ResponseBody
    public Callable<String> callableReq () {
        System.out.println("外部线程：" + Thread.currentThread().getName());

        return new Callable<String>() {

            @Override
            public String call() throws Exception {
                System.out.println("内部线程：" + Thread.currentThread().getName());
                return "callable!";
            }
        };

    }
}
